home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / PROG_TOO / C027B.ZIP / TOP / INST.C < prev    next >
Text File  |  1990-03-30  |  8KB  |  396 lines

  1. /* Copyright (c) 1988 by Sozobon, Limited.  Author: Tony Andrews
  2.  *
  3.  * Permission is granted to anyone to use this software for any purpose
  4.  * on any computer system, and to redistribute it freely, with the
  5.  * following restrictions:
  6.  * 1) No charge may be made other than reasonable charges for reproduction.
  7.  * 2) Modified versions must be clearly marked as such.
  8.  * 3) The authors are not responsible for any harmful consequences
  9.  *    of using this software, even if they result from defects in it.
  10.  */
  11.  
  12. /*
  13.  * Routines dealing with the parsing and output of instructions.
  14.  */
  15.  
  16. #include "top.h"
  17.  
  18. static    void    getarg();
  19. static    int    isreg();
  20.  
  21. /*
  22.  * addinst(bp, op, args) - add an instruction to block 'bp'
  23.  */
  24. void
  25. addinst(bp, op, args)
  26. register BLOCK    *bp;
  27. char    *op, *args;
  28. {
  29.     register INST    *ni;
  30.     register int    i;
  31.     register char    *s;
  32.     char    *arg2 = "";
  33.  
  34.     if (*op == '\0')    /* no instruction there */
  35.         return;
  36.  
  37.     ni = (INST *) alloc(sizeof(INST));
  38.  
  39.     ni->flags = 0;
  40.     ni->opcode = -1;
  41.     ni->next = NULL;
  42.     ni->prev = NULL;
  43.     ni->live = 0;
  44.     ni->rref = ni->rset = 0;
  45.  
  46.     ni->src.areg = ni->dst.areg = 0;
  47.     ni->src.ireg = ni->dst.ireg = 0;
  48.     ni->src.disp = ni->dst.disp = 0;
  49.     ni->src.astr = ni->dst.astr = NULL;
  50.     ni->src.amode = ni->dst.amode = NONE;
  51.  
  52.     /*
  53.      * Link into the block appropriately
  54.      */
  55.     if (bp->first == NULL) {
  56.         bp->first = bp->last = ni;
  57.     } else {
  58.         bp->last->next = ni;
  59.         ni->prev = bp->last;
  60.  
  61.         bp->last = ni;
  62.     }
  63.  
  64.     for (s = op; *s ;s++) {
  65.         /*
  66.          * Pseudo-ops start with a period, so the length
  67.          * specifier can't be the first character.
  68.          */
  69.         if (*s == '.' && s != op) {    /* length specifier */
  70.             *s++ = '\0';
  71.             switch (*s) {
  72.             case 'b':
  73.                 ni->flags |= LENB;
  74.                 break;
  75.             case 'w':
  76.                 ni->flags |= LENW;
  77.                 break;
  78.             case 'l':
  79.                 ni->flags |= LENL;
  80.                 break;
  81.             default:
  82.                 fprintf(stderr, "Bad length spec '%c'\n", *s);
  83.                 exit(1);
  84.             }
  85.         }
  86.     }
  87.  
  88.     for (i=0; opnames[i] ;i++) {
  89.         if (strcmp(op, opnames[i]) == 0) {
  90.             ni->opcode = i;
  91.             break;
  92.         }
  93.     }
  94.  
  95.     if (ni->opcode < 0) {
  96.         fprintf(stderr, "Unknown op '%s'\n", op);
  97.         exit(1);
  98.     }
  99.  
  100.     for (s = args; *s ;s++) {
  101.         /*
  102.          * skip chars in parens, since an operand split can't
  103.          * occur within.
  104.          */
  105.         if (*s == '(') {
  106.             while (*s != ')')
  107.                 s++;
  108.         }
  109.         if (*s == ',') {
  110.             *s++ = '\0';
  111.             arg2 = s;
  112.             break;
  113.         }
  114.     }
  115.  
  116.     getarg(&ni->src, args);
  117.     getarg(&ni->dst, arg2);
  118. }
  119.  
  120. /*
  121.  * delinst(bp, ip) - delete instruction 'ip' in block 'bp'
  122.  */
  123. void
  124. delinst(bp, ip)
  125. BLOCK    *bp;
  126. INST    *ip;
  127. {
  128.     INST    *pi, *ni;    /* previous and next instructions */
  129.  
  130.     pi = ip->prev;
  131.     ni = ip->next;
  132.  
  133.     if (pi != NULL)
  134.         pi->next = ni;
  135.     else
  136.         bp->first = ni;
  137.  
  138.     if (ni != NULL)
  139.         ni->prev = pi;
  140.     else
  141.         bp->last = pi;
  142.  
  143.     /*
  144.      * Free space used by the instruction.
  145.      */
  146.     if (ip->src.astr != NULL)
  147.         free(ip->src.astr);
  148.     if (ip->dst.astr != NULL)
  149.         free(ip->dst.astr);
  150.     free(ip);
  151. }
  152.  
  153. static    void
  154. getarg(op, s)
  155. register struct    opnd    *op;
  156. register char    *s;
  157. {
  158.     extern    long    atol();
  159.     register int    reg;
  160.     register char    *p;
  161.  
  162.     if (*s == '\0') {
  163.         op->amode = NONE;
  164.         return;
  165.     }
  166.  
  167.     if (*s == '#') {                /* immediate data */
  168.         op->amode = IMM;
  169.         s += 1;
  170.         if (isdigit(s[0]) || s[0] == '-')
  171.             op->disp  = atol(s);
  172.         else {
  173.             op->amode |= SYMB;
  174.             op->astr = strsave(s);
  175.         }
  176.         return;
  177.     } else if ((reg = isreg(s)) >= 0) {        /* reg. direct */
  178.         op->amode = REG;
  179.         op->areg = reg;
  180.     } else if (s[0] == '(' || (s[0] == '-' && s[1] == '(')) {
  181.         op->amode = REGI;
  182.         if (s[0] == '-') {
  183.             op->amode |= DEC;
  184.             s++;
  185.         }
  186.         s++;        /* skip the left paren */
  187.         if ((op->areg = isreg(s)) < 0) {
  188.             fprintf(stderr, "bad reg. '%s'\n", s);
  189.             exit(1);
  190.         }
  191.         s += 3;        /* skip the register and right paren */
  192.  
  193.         if (s[0] == '+')
  194.             op->amode |= INC;
  195.     } else if (!isdigit(s[0]) && (s[0] != '-')) {
  196.         op->amode = ABS;
  197.         op->astr = strsave(s);
  198.     } else {
  199.         for (p=s; isdigit(*p) || *p == '-' ;p++)
  200.             ;
  201.         if (*p != '(') {
  202.             /*
  203.              * Must have been absolute, but with an
  204.              * address instead of a symbol.
  205.              */
  206.             op->amode = ABS;
  207.             op->astr = strsave(s);
  208.             return;
  209.         }
  210.         *p++ = '\0';
  211.         op->disp = atol(s);
  212.         s = p;
  213.         if (s[0] == 'p' && s[1] == 'c') {    /* PC relative */
  214.             if (s[2] == ')') {
  215.                 op->amode = PCD;
  216.                 return;
  217.             }
  218.             op->amode = PCDX;
  219.             op->ireg = isreg(s+3);
  220.             if (s[6] == 'l')
  221.                 op->amode |= XLONG;
  222.         } else if ((reg = isreg(s)) >= 0) {
  223.             op->areg = reg;
  224.             if (s[2] == ')') {
  225.                 op->amode = REGID;
  226.                 return;
  227.             }
  228.             op->amode = REGIDX;
  229.             op->ireg = isreg(s+3);
  230.             if (s[6] == 'l')
  231.                 op->amode |= XLONG;
  232.         } else {
  233.             fprintf(stderr, "bad reg. '%s' after disp\n", s);
  234.             exit(1);
  235.         }
  236.     }
  237. }
  238.  
  239. /*
  240.  * characters that can terminate a register name
  241.  */
  242. #define    isterm(c) ((c) == '\0' || (c) == ')' || (c) == ',' || (c) == '.')
  243.  
  244. static    int
  245. isreg(s)
  246. char    *s;
  247. {
  248.     if (s[0] == 'd' && isdigit(s[1]) && isterm(s[2]))
  249.         return D0 + (s[1] - '0');
  250.     if (s[0] == 'a' && isdigit(s[1]) && isterm(s[2]))
  251.         return A0 + (s[1] - '0');
  252.     if (s[0] == 's' && s[1] == 'p' && isterm(s[2]))
  253.         return SP;
  254.  
  255.     return -1;
  256. }
  257.  
  258.  
  259. /*
  260.  * Routines for printing out instructions
  261.  */
  262.  
  263. static    char    *rstr();
  264. static    void    putop();
  265.  
  266. void
  267. putinst(ip)
  268. register INST    *ip;
  269. {
  270.     char    c;
  271.  
  272.     fprintf(ofp, "\t%s", opnames[ip->opcode]);
  273.  
  274.     switch (ip->flags) {
  275.     case LENB:
  276.         c = 'b';
  277.         break;
  278.     case LENW:
  279.         c = 'w';
  280.         break;
  281.     case LENL:
  282.         c = 'l';
  283.         break;
  284.     default:
  285.         c = '\0';
  286.         break;
  287.     }
  288.     if (c)
  289.         fprintf(ofp, ".%c", c);
  290.  
  291.     if (ip->src.amode != NONE) {
  292.         fprintf(ofp, "\t");
  293.         putop(&ip->src);
  294.     }
  295.  
  296.     if (ip->dst.amode != NONE) {
  297.         fprintf(ofp, ",");
  298.         putop(&ip->dst);
  299.     }
  300. #ifdef    DEBUG
  301.     if (debug)
  302.         fprintf(ofp, "\t\t* ref(%04x), set(%04x), live(%04x)",
  303.             reg_ref(ip), reg_set(ip), ip->live);
  304. #endif
  305.     fprintf(ofp, "\n");
  306. }
  307.  
  308. static    void
  309. putop(op)
  310. register struct    opnd    *op;
  311. {
  312.     switch (op->amode & MMASK) {
  313.     case NONE:
  314.         break;
  315.     case REG:
  316.         fprintf(ofp, "%s", rstr(op->areg));
  317.         break;
  318.     case IMM:
  319.         if (op->amode & SYMB)
  320.             fprintf(ofp, "#%s", op->astr);
  321.         else
  322.             fprintf(ofp, "#%ld", op->disp);
  323.         break;
  324.     case ABS:
  325.         fprintf(ofp, "%s", op->astr);
  326.         break;
  327.     case REGI:
  328.         if (op->amode & DEC)
  329.             fprintf(ofp, "-");
  330.         fprintf(ofp, "(%s)", rstr(op->areg));
  331.         if (op->amode & INC)
  332.             fprintf(ofp, "+");
  333.         break;
  334.     case REGID:
  335.         fprintf(ofp, "%ld(%s)", op->disp, rstr(op->areg));
  336.         break;
  337.     case REGIDX:
  338.         fprintf(ofp, "%ld(%s,", op->disp, rstr(op->areg));
  339.         fprintf(ofp, "%s.%c)", rstr(op->ireg),
  340.             (op->amode & XLONG) ? 'l' : 'w');
  341.         break;
  342.     case PCD:
  343.         fprintf(ofp, "%ld(pc)", op->disp);
  344.         break;
  345.     case PCDX:
  346.         fprintf(ofp, "%ld(pc,%s.%c)", op->disp, rstr(op->ireg),
  347.             (op->amode & XLONG) ? 'l' : 'w');
  348.         break;
  349.     default:
  350.         fprintf(stderr, "bad addr. mode in putop: %d\n", op->amode);
  351.         exit(1);
  352.     }
  353. }
  354.  
  355. static    char *
  356. rstr(r)
  357. register char    r;
  358. {
  359.     static    char    buf[3];
  360.  
  361.     if (r == SP) {
  362.         buf[0] = 's';
  363.         buf[1] = 'p';
  364.     } else if (r >= A0 && r <= A6) {
  365.         buf[0] = 'a';
  366.         buf[1] = '0' + (r - A0);
  367.     } else {
  368.         buf[0] = 'd';
  369.         buf[1] = '0' + (r - D0);
  370.     }
  371.     buf[2] = '\0';
  372.  
  373.     return buf;
  374. }
  375.  
  376. /*
  377.  * opeq(op1, op2) - test equality of the two instruction operands
  378.  */
  379. bool
  380. opeq(op1, op2)
  381. struct    opnd    *op1, *op2;
  382. {
  383.     if (op1->amode != op2->amode || op1->areg != op2->areg ||
  384.         op1->ireg  != op2->ireg  || op1->disp != op2->disp)
  385.         return FALSE;
  386.  
  387.     if (op1->astr == NULL)
  388.         return (op2->astr == NULL);
  389.     else {
  390.         if (op2->astr == NULL)
  391.             return FALSE;
  392.  
  393.         return (strcmp(op1->astr, op2->astr) == 0);
  394.     }
  395. }
  396.